// Service ControlDlg.cpp : implementation file
//

#include "stdafx.h"
#include <winver.h>
#include "winsvc.h"
#include "Service Control.h"
#include "Service ControlDlg.h"
#include "DlgProxy.h"
#include "casbase.h"
#include "StopMsgDlg.h"
#include "SingleServDlg.h"


#ifdef _DEBUG
//#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//SERVICE INFORMATION
#define MAX_SERVICE_COUNT 50
#define SERVICE_CONTROL_USER 128
#define SERVICE_CONTROL_SETSTOPMSG (SERVICE_CONTROL_USER + 0)
#define SERVICE_CONTROL_SETLOGLEVEL (SERVICE_CONTROL_USER + 1)

//DEFINE THE COLUMNS OF THE TABLE, FOR EASY CHANGES
#define NAMECOL 0
#define STATECOL 1
#define STOPCOL 2
#define EXITCOL 3
#define VERCOL 4

//TIMER INFORMATION (FOR REFRESH)
#define REFRESH 1000  //1 second
#define IDT_TIMER_0  WM_USER + 200  //The refresh timer

//External c calls for the kill and getpid procs
extern int _cdecl tlistmain(/*int argc,*/ char * pname);
extern int _cdecl killmain(int argc/*,char *argv[]*/);

// CSN-8334 - Move USERS stats out of server.ini
#define USRSTAT	TEXT("USERS")

#define SERVICE_BASENAME "CasinoApp"

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CServiceControlDlg dialog

IMPLEMENT_DYNAMIC(CServiceControlDlg, CDialog);

CServiceControlDlg::CServiceControlDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CServiceControlDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CServiceControlDlg)
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	m_pAutoProxy = NULL;
	m_bKillPossible = true;
}

CServiceControlDlg::~CServiceControlDlg()
{
	// If there is an automation proxy for this dialog, set
	//  its back pointer to this dialog to NULL, so it knows
	//  the dialog has been deleted.
	if (m_pAutoProxy != NULL)
		m_pAutoProxy->m_pDialog = NULL;
}

void CServiceControlDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CServiceControlDlg)
	DDX_Control(pDX, IDC_LSERVICELIST, m_LCServiceList);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CServiceControlDlg, CDialog)
	//{{AFX_MSG_MAP(CServiceControlDlg)	
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_WM_CLOSE()
	ON_NOTIFY(NM_DBLCLK, IDC_LSERVICELIST, OnDblclkLservicelist)
	ON_NOTIFY(LVN_COLUMNCLICK, IDC_LSERVICELIST, OnColumnclickLservicelist)
	ON_WM_TIMER()
	ON_BN_CLICKED(IDC_BTNSTARTALL, OnBtnstartall)
	ON_BN_CLICKED(IDC_BTNSTOPALL, OnBtnstopall)
	ON_NOTIFY(LVN_ITEMCHANGED, IDC_LSERVICELIST, OnItemChangedInList)
	ON_BN_CLICKED(IDC_BTNSETSTOPMSG, OnBtnsetstopmsg)
	ON_BN_CLICKED(IDC_BTNSTART, OnBtnstart)
	ON_BN_CLICKED(IDC_BTNSTOP, OnBtnstop)
	ON_BN_CLICKED(IDC_BTNKILL, OnBtnkill)
	ON_BN_CLICKED(IDC_BTNKILLALL, OnBtnkillall)
	ON_CBN_SELCHANGE(IDC_COMBOLOGLEVEL, &CServiceControlDlg::OnCbnSelchangeCombologlevel)
	//}}AFX_MSG_MAP
//	ON_CBN_DROPDOWN(IDC_COMBOLOGLEVEL, &CServiceControlDlg::OnCbnDropdownCombologlevel)
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CServiceControlDlg message handlers

BOOL CServiceControlDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	//Initialize Member Variables
	m_iNumServices = 0; //The number of listed services
	CasinoBase::load(); //Get the casino basename
	m_csBaseName = CasinoBase::basename; //The casino basename
	m_bIsOneStartable = false; //Is there a service listed that can be started?
	m_bIsOneStoppable = false; //Is there a service listed that can be started?
	m_bCanSetStopMsg = false;  //Is there a service listed that can have its stopmsg set?
	m_bStarting = false; //Is there a batch process going on?
	m_bSortAscending = true; //Which way is the current column sorted?
	m_uRefreshTimer = 0; //The UID for the refresh timer
	m_iSortedCol = -1; //Which column are we sorting by?
	m_iFocusIndex = -1; //What line of the list has the focus?
	m_iLastFocusIndex = 0; //What line of the list just lost focus?
	m_iaLastFocus[m_iLastFocusIndex] = m_iFocusIndex; //And an array of the rest

	//Initialize the layout of the list control -- The total width is 512 dlu
	m_LCServiceList.SetExtendedStyle(m_LCServiceList.GetExtendedStyle()|LVS_EX_GRIDLINES);
	m_LCServiceList.SetExtendedStyle(m_LCServiceList.GetExtendedStyle()|LVS_EX_FULLROWSELECT);
	m_LCServiceList.SetExtendedStyle(m_LCServiceList.GetExtendedStyle()|LVS_EX_HEADERDRAGDROP);
	m_LCServiceList.InsertColumn(NAMECOL, "Service Name");
	m_LCServiceList.InsertColumn(STATECOL, "State");
	m_LCServiceList.InsertColumn(EXITCOL, "Exit Code");
	m_LCServiceList.InsertColumn(STOPCOL, "Stop Message");
    m_LCServiceList.InsertColumn(VERCOL, "Version");
	m_LCServiceList.SetColumnWidth(NAMECOL, 90);
	m_LCServiceList.SetColumnWidth(STATECOL, 120);
	m_LCServiceList.SetColumnWidth(EXITCOL, 85);
	m_LCServiceList.SetColumnWidth(STOPCOL, 157);
    m_LCServiceList.SetColumnWidth(VERCOL, 80);


	//Retitle the window to reflect the server name
	SetWindowTitle();

	//Drop unused items from the system menu
	CMenu * mnu = GetSystemMenu(FALSE);
	mnu->EnableMenuItem(SC_MAXIMIZE,MF_BYCOMMAND | MF_GRAYED);
	mnu->EnableMenuItem(SC_SIZE,MF_BYCOMMAND | MF_GRAYED);

	//Populate the listview with the services
	GetServiceList();

	//Get a first update
	UpdateAll();

	//Select the first item
	SetFocusOnly(0);

	// Set log level in combo
	int iLogLevel = CasinoBase::getInt32OptEx("LOG", "LogLevel", 0);
	if (iLogLevel >= 1 && iLogLevel <= 5)
	{
		CComboBox* cmbLogLevel = (CComboBox*)GetDlgItem(IDC_COMBOLOGLEVEL);
		cmbLogLevel->SetCurSel(iLogLevel-1);
	}

	//Start the refresh timer
	m_uRefreshTimer = StartTimer(REFRESH);

	//Start out with the list selected
	m_LCServiceList.SetFocus();

	return FALSE;  // return TRUE  unless you set the focus to a control
}


void CServiceControlDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	//This is the default handler for syscommands
	//Only "about" is overloaded (for now)
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}


void CServiceControlDlg::OnPaint() 
{

	//Windows doesn't draw iconized views automatically for 
	//Dialog based apps. Do it ourself.
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}


HCURSOR CServiceControlDlg::OnQueryDragIcon()
{
	//We just set the minimized drag icon to our standard one
	return (HCURSOR) m_hIcon;
}


// Automation servers should not exit when a user closes the UI
//  if a controller still holds on to one of its objects.  These
//  message handlers make sure that if the proxy is still in use,
//  then the UI is hidden but the dialog remains around if it
//  is dismissed.

void CServiceControlDlg::OnClose() 
{
	if (CanExit())
		CDialog::OnClose();
}


void CServiceControlDlg::OnOK() 
{
	if (CanExit())
		CDialog::OnOK();
}


void CServiceControlDlg::OnCancel() 
{
	if (CanExit())
		CDialog::OnCancel();
}


BOOL CServiceControlDlg::CanExit()
{
	//Disable automation for now
	/*
	// If the proxy object is still around, then the automation
	//  controller is still holding on to this application.  Leave
	//  the dialog around, but hide its UI.
	if (m_pAutoProxy != NULL)
	{
		ShowWindow(SW_HIDE);
		return FALSE;
	}
	*/
	return TRUE;
	
}


void CServiceControlDlg::GetServiceList()
{
	//We only call this once, and it populates the first column of the list
	SC_HANDLE hSCM = openSCM();
	ENUM_SERVICE_STATUS services[50];
    SC_HANDLE sc_h=NULL;
	DWORD i, needed, num, resume;
	BOOL result;
	CString csFullBaseName=SERVICE_BASENAME; //The service basename
	LVITEM lviService; //The service as a list item
	CString csShortName = "Default"; //Used for String Formatting.
	CString csLongName = "Default"; //Used for String Formatting.

	//Make sure we still have SCM privileges
	if (!hSCM)
		return;


	//Get the Casino Base Name
	csFullBaseName = m_csBaseName;
	csFullBaseName.Trim();

	//Initialize the LVITEM
	lviService.mask = LVIF_TEXT;
	lviService.iItem = 0;
	lviService.iSubItem = 0;

	//Search through the whole service list, looking for RTG services	
	resume = needed = num = 0;
	while (1)
	{
		//Get the list of services
		result = EnumServicesStatus(hSCM, SERVICE_WIN32,
			SERVICE_ACTIVE | SERVICE_INACTIVE, (LPENUM_SERVICE_STATUS)services,
			sizeof(ENUM_SERVICE_STATUS) * 50, &needed, &num, &resume);

		if (result || (!result && GetLastError() == ERROR_MORE_DATA))
		{
			//Find the ones with the basename in them
			for (i = 0; i < num; i++)
			{
            //RPF 20091015 We need to avoid getting USD & USDFUN servers mixed
            //therefore we compare now with the display name of the service and put a extra blank
            const char* pszBaseName = strstr(services[i].lpDisplayName, csFullBaseName + " ");
				if (pszBaseName != NULL &&
					m_iNumServices < MAX_SERVICE_COUNT)
				{
					if ( isdigit(pszBaseName[csFullBaseName.GetLength()]) )
					{
						// Differentiate between devpart and devpart02 casinos
						continue;
					}
                    
                    //Version buffers
                    BYTE *pBuffer;
                    LPVOID obuffer = 0;

					//We have one here.
                    //Lets find out version of this service
                    sc_h=OpenService(hSCM,services[i].lpServiceName,SERVICE_QUERY_CONFIG);
                    if(sc_h==NULL)
                        {
                        printf("OpenService failed (%d)", GetLastError());
                        continue;
                        }
                    if(sc_h!=NULL)
                        {
                            //20100525 RPF
                            // Get the configuration information.
                            LPQUERY_SERVICE_CONFIG lpsc; 
                            DWORD dwBytesNeeded, cbBufSize, dwError; 


                            if( !QueryServiceConfig( 
                                sc_h, 
                                NULL, 
                                0, 
                                &dwBytesNeeded))
                            {
                                dwError = GetLastError();
                                if( ERROR_INSUFFICIENT_BUFFER == dwError )
                                {
                                    cbBufSize = dwBytesNeeded;
                                    lpsc = (LPQUERY_SERVICE_CONFIG) LocalAlloc(LMEM_FIXED, cbBufSize);
                                }
                                else
                                {
                                    printf("QueryServiceConfig failed (%d)", dwError);
                                    
                                }
                            }
  
                            if( !QueryServiceConfig( 
                                sc_h, 
                                lpsc, 
                                cbBufSize, 
                                &dwBytesNeeded) ) 
                            {
                                printf("QueryServiceConfig failed (%d)", GetLastError());
                                
                            }
                            
                            CloseServiceHandle(sc_h); 
                            //Find Out exe file version
                            CString str;
                            str=lpsc->lpBinaryPathName;
                            str.Replace('"','|');
                            str.Replace("|","");
                                                      
                             DWORD dwHandle;
                             DWORD dwLen = GetFileVersionInfoSize(str, &dwHandle);
                            
                             UINT   Len    = 0;

                             if (dwLen) {
                              pBuffer = (BYTE*)malloc(dwLen);
                              if (pBuffer) {
                               if (GetFileVersionInfo(str, dwHandle, dwLen, pBuffer)) {
                                VerQueryValue(pBuffer,"\\StringFileInfo\\040904B0\\FileVersion", &obuffer, &Len);
                               }
                              
                              }
                             }

                                       
                            //20100525 END
                        
                        }
					//Set up the LVITEM
					csLongName = services[i].lpDisplayName;
					csShortName = StripCasinoName(csLongName);
					lviService.pszText = csShortName.GetBuffer();
					lviService.iItem = m_iNumServices;
                    
                    
					
					//Add it to the Listview (in the first column)
					int item=m_LCServiceList.InsertItem(&lviService);
                    m_LCServiceList.SetItemText(item,VERCOL,(char*)obuffer);
					csShortName.ReleaseBuffer();

					//Add it to the arrays (the one by name is used to look up services
					m_pcaServicesShortName[m_iNumServices] = csShortName;
					m_pcaServices[m_iNumServices]          = services[i].lpServiceName;
					m_pcaServicesAppName[m_iNumServices]   = StripAppName(services[i].lpServiceName);
					++m_iNumServices;

                    free(pBuffer);

				}
			}
			
			if (result)
				break;	// got them all
		}
		else
			break;		// problem with EnumServicesStatus
	}

	//At this point, all of the RTG Casino Services are in the listview, in the order they are in services
	//There is also a list of services by servicename in m_pcaServices, where the indexes are the same as 
	//The list of services by shortname, m_pcaServicesShortName. 
    CloseServiceHandle(hSCM);

}


void CServiceControlDlg::SetWindowTitle()
{
	CString csCasino;
	CString csFullTitle;
	
	//Get the casino name
	CasinoBase::load();
	csCasino.Format("%s",CasinoBase::basename);
	csFullTitle = "BRNG Service Control - " + csCasino;

	this->SetWindowText(csFullTitle);

}


CString CServiceControlDlg::StripCasinoName(CString csServiceName)
{
	//Remove "RTG Casino " and the basename, and return the stripped string
	CString csShortName;

	//The size of the casino name will vary. Add it to 11 - the size of "RTG Casino "
	int iBaseSize = m_csBaseName.GetLength();
	iBaseSize += 11;

	// Skip any whitespace in the name
	while ( isspace(csServiceName[iBaseSize]) )
		iBaseSize++;

	//Now delete the beginning part of the string
	csServiceName.Delete(0, iBaseSize);

	//Also strip off " service" from the end
	int iTotalSize = csServiceName.GetLength();
	iTotalSize -= 8;
	
	csShortName = csServiceName.Left(iTotalSize); //Copy to avoid ref count decrement

	return csShortName;
}


CString CServiceControlDlg::StripAppName(CString csServiceName)
{
	CString app;
	CString base = SERVICE_BASENAME;
	base.Append(CasinoBase::basename);

	app = csServiceName.Right(csServiceName.GetLength() - base.GetLength());

	return app;
}


CString CServiceControlDlg::MakeFullName(CString csShortName)
{

	//Insert "RTG Casino " and the basename to the start, and return the expanded string
	CString csFullName("Casino App ");
	csFullName = m_csBaseName;
	csFullName += csShortName;

	return csFullName;
}


void CServiceControlDlg::OnDblclkLservicelist(NMHDR* pNMHDR, LRESULT* pResult) 
{
	//A double click has been received in the list itself
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

	//Bring up the singleserv dialog, with the right service
	CSingleServDlg ssdlg;
	int nIndex;
	int pid;
	CString Msg;
	CString lShortName;
	CString csSpace = " ";

	//Figure out which one was clicked
	nIndex = pNMListView->iItem;
	lShortName = m_LCServiceList.GetItemText(nIndex,0);

	//And populate the dialog
	ssdlg.m_csShortName = csSpace + m_LCServiceList.GetItemText(nIndex,0);
	ssdlg.m_csState = csSpace + m_LCServiceList.GetItemText(nIndex,1);
	ssdlg.m_csStopMsg = csSpace + m_LCServiceList.GetItemText(nIndex,2);
	ssdlg.m_csExitCode = csSpace + m_LCServiceList.GetItemText(nIndex,3);
	pid = GetProcessId(lShortName);
	if(pid == 0)
	{
		Msg = "<Not Running>";
	}
	else
	{
		Msg.Format("%d",pid);
	}
	ssdlg.m_csProcessId = csSpace + Msg;
	ssdlg.m_csFullName = csSpace + MakeServiceName(lShortName);

	//Now show the dialog
	if(ssdlg.DoModal()!=IDOK)
		return;

	//Issue the command they chose
	if(ssdlg.m_bDoStart)
	{
		//Start it
		SetFocusOnly(nIndex);
		OnBtnstart();
	}
	else if(ssdlg.m_bDoStop)
	{
		//Stop it
		SetFocusOnly(nIndex);
		OnBtnstop();
	}
	else if(ssdlg.m_bDoKill)
	{
		//Kill it
		SetFocusOnly(nIndex);
		OnBtnkill();
	}
	else if(ssdlg.m_bDoSetStopMsg)
	{
		SetFocusOnly(nIndex);
		OnBtnsetstopmsg();	
	}

	//We handled the message
	*pResult = 0;
}


CString CServiceControlDlg::MakeServiceName(CString csShortName)
{
	//Find it in m_pcaServicesShortName, and then use the index to get the service
	//name from m_pcaServices

	//We assert that the string must be there, or else we'll return "NOT FOUND"
	CString csSvcName("NOT FOUND");
	bool bFound = false;
	int iFoundIndex = 0;

	while((!bFound) && (iFoundIndex <= MAX_SERVICE_COUNT))
	{
		if(csShortName.Compare(m_pcaServicesShortName[iFoundIndex])==0)
		{
			bFound = true;
		}
		else
		{
			iFoundIndex++;
		}
	}


	//At this point, iFoundIndex is the index of the service, or MAX_SERVICE_COUNT+1 if not found
	if(iFoundIndex <= MAX_SERVICE_COUNT)
	{
		csSvcName =  /*strdup*/ m_pcaServices[iFoundIndex];
	}

	return csSvcName;
}

CString CServiceControlDlg::MakeAppName(CString csShortName)
{
	// Find app name from m_pcaServicesAppName. Return "NOT FOUND" if it wasn't found
	CString csSvcName("NOT FOUND");
	bool bFound     = false;
	int iFoundIndex = 0;

	while ((!bFound) && (iFoundIndex <= MAX_SERVICE_COUNT))
	{
		if (csShortName.Compare(m_pcaServicesShortName[iFoundIndex]) == 0)
		{
			bFound = true;
		}
		else
		{
			iFoundIndex++;
		}
	}

	if (iFoundIndex <= MAX_SERVICE_COUNT)
	{
		csSvcName = m_pcaServicesAppName[iFoundIndex];
	}

	return csSvcName;
}

void CServiceControlDlg::UpdateSingleItem(CString csShortName, CString csAppName)
{
	//ListCtrlStructures
	LVITEM lvi;	
	DWORD cchTextBuf(1024);
	TCHAR szLVTextBuf[1024];
	

	//Service Structures
	SC_HANDLE hSCM;
	SC_HANDLE hService;
	SERVICE_STATUS sStatus;
	DWORD dwState = 0xFFFFFFFF;
	DWORD dwError = 0xFFFFFFFF;
	CString csState;
	CString csExitCode;
	CString csStopMsg;
	CString csServiceName;

	//Get the Service from the Service Manager
	csServiceName = MakeServiceName(csShortName);
	hSCM = openSCM();
	hService = openSvc(hSCM, csServiceName);


	//Get a valid State and Error/Exit Code
	if(hService) // We got it
	{
		//Fill the Service Status Structure
		memset(&sStatus,0,sizeof(sStatus));
		if(QueryServiceStatus(hService,&sStatus))
		{
			dwError = sStatus.dwWin32ExitCode;
			dwState = sStatus.dwCurrentState;

			//Need a different query for running services
			if((dwState == SERVICE_RUNNING) && 
				::ControlService(hService,SERVICE_CONTROL_INTERROGATE, &sStatus))
			{
				dwError = sStatus.dwWin32ExitCode;
				dwState = sStatus.dwCurrentState;
			}	
		}
		else
		{
			dwError = GetLastError();
		}


	}
	
	//We're done with the Service Manager, so clean up now
	CloseServiceHandle(hService);
	CloseServiceHandle(hSCM);


	//Handle the Error/Exit code first (subitem 3), it's generic.
	if(dwError == 0xFFFFFFFF)
	{
		//We don't know
		csExitCode = "<unknown>";
	}
	else
	{
		//Just write it in
		csExitCode.Format("0x%8.8lx (%d)", dwError, dwError);
	}


	//Now Fill in State depending on dwState
	switch (dwState)
	{
		case SERVICE_START_PENDING:
			csState = "Start Pending";
			break;

		case SERVICE_RUNNING:
			csState = "Running - ";
            csState += GetUserCountCS(csAppName);
			csState += " Users";
			m_bIsOneStoppable = true;
			break;

		case SERVICE_PAUSE_PENDING:
			csState = "Pause Pending";
			csState += GetUserCountCS(csAppName);
			csState += " Users";
			break;

		case SERVICE_PAUSED:
			csState = "Paused";
			break;

		case SERVICE_CONTINUE_PENDING:
			csState = "Continue Pending";
			break;

		case SERVICE_STOP_PENDING:
			csState = "Stop Pending - ";
			csState += GetUserCountCS(csAppName);
			csState += " Users";
			break;

		case SERVICE_STOPPED:
			csState = "Stopped";
			m_bIsOneStartable = true;
			break;

		default:
			csState = "<Unknown>";
			break;
	}

	//Finally, set the stop message
	csStopMsg = GetStopMsg(csServiceName);

	//Okay, now update the list control

	//Create a shell LVITEM to work with
	lvi.iItem = -1;
	lvi.iSubItem = 0;
	lvi.mask = LVIF_TEXT;
	lvi.pszText = szLVTextBuf;
	lvi.cchTextMax = cchTextBuf;

	//And get the right one from the listctrl.
	GetItemFromName(csShortName,&lvi);

	//Update it with all the new info

	//State
	lvi.iSubItem = STATECOL;
	lvi.pszText = csState.GetBuffer();
	m_LCServiceList.SetItem(&lvi);
	csState.ReleaseBuffer();


	//Exit Code
	lvi.iSubItem = EXITCOL;
	lvi.pszText =  csExitCode.GetBuffer();
	m_LCServiceList.SetItem(&lvi);
	csExitCode.ReleaseBuffer();

	//Stop Message
	lvi.iSubItem = STOPCOL;
	lvi.pszText =  csStopMsg.GetBuffer();
	m_LCServiceList.SetItem(&lvi);
	csStopMsg.ReleaseBuffer();

}


void CServiceControlDlg::GetItemFromName(CString csShortName, LVITEM *plvi)
{
	//ListCtrlStructures
	LVFINDINFO lvfind;

	//Helpers
	int nIndex;


	//Find the index of the item in listview
	lvfind.flags = LVFI_PARTIAL|LVFI_STRING;
	lvfind.psz =  /*strdup*/ csShortName.GetBuffer(csShortName.GetLength());
	nIndex=m_LCServiceList.FindItem(&lvfind);
	if(nIndex == -1)
	{
		AfxMessageBox("UpdateSingleItem - Service Not Found",MB_OK);
	}
	else
	{
		//Create a shell LVITEM to hold it.
		plvi->iItem = nIndex;

		//And get it.
		m_LCServiceList.GetItem(plvi);
	}
}


CString CServiceControlDlg::GetUserCountCS(CString csServiceName)
{
    /*
	//We look it up in the registry
	CString csUserCount;
	HKEY hkey;
	CHAR szKey[256];
	DWORD users;
	DWORD dwType;
	DWORD dwSize;

	//Build the path to the key
	strcpy_s(szKey, sizeof(szKey), "SYSTEM\\CurrentControlSet\\Services\\");
	strcat_s(szKey, sizeof(szKey), csServiceName);
	strcat_s(szKey, sizeof(szKey), "\\Status");

	//Get the reg key
	if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,szKey,0,KEY_QUERY_VALUE,&hkey))
	{
		dwType = REG_DWORD;
		dwSize = sizeof(DWORD);

		//Use it to get the user count, if one exists
		if(ERROR_SUCCESS == RegQueryValueEx(hkey,"Users",NULL,&dwType,(BYTE*)&users,&dwSize))
		{
			//We actually have a valid number
			csUserCount.Format("%lu",users);
		}
		else
		{
			csUserCount = "0";
		}

		RegCloseKey(hkey);

	}
	else
	{
		csUserCount = "0";

	}

	return csUserCount;
    */

    //RPF 20090723
    //THE STATUS REGISTRY KEY IS NO LONGER USED TO UPDATE THE COUNT OF PLAYERS
    //NOW WE USE THE INI FILE TO STORE AND UPDATE THE COUNT OF PLAYERS
    //UPDATE NUMBERS OF PLAYERS PLAYING
	// CSN-8334 - Move USERS stats out of server.ini
    char szUserCount[10];
	CasinoBase::getStrOptEx(csServiceName.GetBuffer(),USRSTAT,"0",szUserCount,10);
    return CString(szUserCount);

}


CString CServiceControlDlg::GetStopMsg(CString csServiceName)
{
	//We look it up in the registry
	char msg[31];
	CString csStopMsg;
	HKEY hkey;
	CHAR szKey[256];
	DWORD dwType;
	DWORD dwSize;

	//Build the path to the key
	msg[0] = '\0';
	strcpy_s(szKey, sizeof(szKey), "SYSTEM\\CurrentControlSet\\Services\\");
	strcat_s(szKey, sizeof(szKey), csServiceName);
	strcat_s(szKey, sizeof(szKey), "\\StopMsg");

	//Get the reg key
	if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,szKey,0,KEY_QUERY_VALUE,&hkey))
	{
		dwType = REG_SZ;
		dwSize = 31;

		RegQueryValueEx(hkey,"Msg",NULL,&dwType,(BYTE*)&msg,&dwSize);

		csStopMsg = msg;

		if(csStopMsg.IsEmpty())
		{
			csStopMsg = "<None>";
		}

		//Close the key
		RegCloseKey(hkey);
	}
	else
	{
		csStopMsg = "<None>";
	}
	
	return csStopMsg;
}


void CServiceControlDlg::UpdateAll()
{
	//Loop through the services,
	//Calling UpdateSingleItem for each one

	//Turn off redrawing -- we'll do it at the end.
	m_LCServiceList.SetRedraw(FALSE);


	//Also, use this run to set the start and stop all buttons
	m_bIsOneStartable = false;
	m_bIsOneStoppable = false;
	
	int nIndex;
	for(nIndex = 0; nIndex < m_iNumServices; nIndex++)
	{
		//Update each service listed individually
		UpdateSingleItem(m_pcaServicesShortName[nIndex], m_pcaServicesAppName[nIndex]);
	}

	if(!m_bStarting)
	{
		//Set the start, stop, and setstopmsg buttons		
		SetButtonStates();

		//Set the start and stop all buttons
		CButton* cBTN;
		if(!m_bIsOneStartable)
		{
			//Disable "Start All" Button
			cBTN = (CButton *) GetDlgItem(IDC_BTNSTARTALL);
			cBTN->EnableWindow(FALSE);
		}
		else
		{
			//Enable "Start All" Button
			cBTN = (CButton *) GetDlgItem(IDC_BTNSTARTALL);
			cBTN->EnableWindow(TRUE);
		}

		if(!m_bIsOneStoppable)
		{
			//Disable "Stop All" Button
			cBTN = (CButton *) GetDlgItem(IDC_BTNSTOPALL);
			cBTN->EnableWindow(FALSE);

			//Disable "Kill All" Button
			cBTN = (CButton *) GetDlgItem(IDC_BTNKILLALL);
			cBTN->EnableWindow(FALSE);
		}
		else
		{
			//Enable "Stop All" Button
			cBTN = (CButton *) GetDlgItem(IDC_BTNSTOPALL);
			cBTN->EnableWindow(TRUE);

			//Enable "Kill All" Button
			cBTN = (CButton *) GetDlgItem(IDC_BTNKILLALL);
			cBTN->EnableWindow(TRUE);

		}

		// Ensure that "Kill All" is disabled if we believe that the user
		// doesn't have access to do so
		if (!m_bKillPossible)
		{
			cBTN = (CButton *) GetDlgItem(IDC_BTNKILLALL);
			cBTN->EnableWindow(FALSE);
		}
		
	}
		//Redraw and invalidate
	m_LCServiceList.SetRedraw(TRUE);
	m_LCServiceList.Invalidate(FALSE);
	m_LCServiceList.UpdateWindow();
	//m_LCServiceList.SetFocus();

}


bool CServiceControlDlg::SortTextItems(int nCol, bool bAscending, int low, int high)
{
	//A helper function to sort the list control by any column.
	
	if( nCol >= 4)
		return FALSE;

	if( high == -1 ) high = m_LCServiceList.GetItemCount() - 1;

	int lo = low;
	int hi = high;


	CString midItem;

	if( hi <= lo ) return FALSE;

	midItem = m_LCServiceList.GetItemText( (lo+hi)/2, nCol );

	// loop through the list until indices cross
	while( lo <= hi )
	{
		// rowText will hold all column text for one row
		CStringArray rowText;

		// find the first element that is greater than or equal to 
		// the partition element starting from the left Index.
		if( bAscending )
			while( ( lo < high ) && ( m_LCServiceList.GetItemText(lo, nCol) < midItem ) )
				++lo;
		else
			while( ( lo < high ) && ( m_LCServiceList.GetItemText(lo, nCol) > midItem ) )
				++lo;

		// find an element that is smaller than or equal to 
		// the partition element starting from the right Index.
		if( bAscending )
			while( ( hi > low ) && ( m_LCServiceList.GetItemText(hi, nCol) > midItem ) )
				--hi;
		else
			while( ( hi > low ) && ( m_LCServiceList.GetItemText(hi, nCol) < midItem ) )
				--hi;

		// if the indexes have not crossed, swap
		// and if the items are not equal
		if( lo <= hi )
		{
			// swap only if the items are not equal
			if( m_LCServiceList.GetItemText(lo, nCol) != m_LCServiceList.GetItemText(hi, nCol))
			{
				// swap the rows
				LV_ITEM lvitemlo, lvitemhi;
				int nColCount = 4;
				rowText.SetSize( nColCount );
				int i;
				for( i=0; i<nColCount; i++)
					rowText[i] = m_LCServiceList.GetItemText(lo, i);
				lvitemlo.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
				lvitemlo.iItem = lo;
				lvitemlo.iSubItem = 0;
				lvitemlo.stateMask = LVIS_CUT | LVIS_DROPHILITED | 
						LVIS_FOCUSED |  LVIS_SELECTED | 
						LVIS_OVERLAYMASK | LVIS_STATEIMAGEMASK;

				lvitemhi = lvitemlo;
				lvitemhi.iItem = hi;

				m_LCServiceList.GetItem( &lvitemlo );
				m_LCServiceList.GetItem( &lvitemhi );

				for( i=0; i<nColCount; i++)
					m_LCServiceList.SetItemText(lo, i, m_LCServiceList.GetItemText(hi, i));

				lvitemhi.iItem = lo;
				m_LCServiceList.SetItem( &lvitemhi );

				for( i=0; i<nColCount; i++)
					m_LCServiceList.SetItemText(hi, i, rowText[i]);

				lvitemlo.iItem = hi;
				m_LCServiceList.SetItem( &lvitemlo );
			}

			++lo;
			--hi;
		}
	}

	// If the right index has not reached the left side of array
	// must now sort the left partition.
	if( low < hi )
		SortTextItems( nCol, bAscending , low, hi);

	// If the left index has not reached the right side of array
	// must now sort the right partition.
	if( lo < high )
		SortTextItems( nCol, bAscending , lo, high );

	return TRUE;

}


void CServiceControlDlg::OnColumnclickLservicelist(NMHDR* pNMHDR, LRESULT* pResult) 
{
	//The user clicked in the column header, so sort the column

	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

    // User clicked on header using left mouse button
	// Sort by that column or, if that's already the
	// Column we're sorting by, reverse the sort order
    if( pNMListView->iSubItem == m_iSortedCol )
            m_bSortAscending = !m_bSortAscending;
    else
            m_bSortAscending = TRUE;

	//Remember which one we're sorting on
    m_iSortedCol = pNMListView->iSubItem;
	
	//Don't redraw during sort
	m_LCServiceList.SetRedraw(FALSE);
    SortTextItems( m_iSortedCol, m_bSortAscending, 0, (m_iNumServices -1) );
	m_LCServiceList.SetRedraw(TRUE);

	*pResult = 0;
}


void CServiceControlDlg::OnTimer(UINT nIDEvent) 
{
	//It's time for a refresh!

	if(nIDEvent == m_uRefreshTimer)
	{
		KillTimer(nIDEvent);
		UpdateAll();
		m_uRefreshTimer = StartTimer(REFRESH);
	}


	CDialog::OnTimer(nIDEvent);
}

UINT CServiceControlDlg::StartTimer(UINT uDuration)
{
		//Start a timer, with a duration of uDuration Milliseconds
		UINT TimerVal;

        TimerVal = SetTimer(IDT_TIMER_0, uDuration, NULL);
        if (TimerVal == 0)
        {
                MessageBox ("Unable to obtain timer","IDT_TIMER_0",MB_OK|MB_SYSTEMMODAL);
        }

        return TimerVal;

}


void CServiceControlDlg::StartServiceByName(CString csShortName)
{
	//Given an individual short name, starts the associated service.

	//Mostly ugly SERVICE structs
	CString csServiceName;
	BOOL bStartResult;
	DWORD dwError;
	SC_HANDLE hSCM;
	SC_HANDLE hService;

	//Get the service name
	csServiceName = MakeServiceName(csShortName);

	//Open the service handler
	hSCM = openSCM();
	//And get the handle of the service
	hService = openSvc(hSCM, csServiceName);

	//Try to start it. If it fails, we'll find out at the next update
	bStartResult = StartService(hService,0,NULL);
	if(!bStartResult)
	{
		//Get the error for debugging
		dwError = GetLastError();
	}

	//Clean Up
	CloseServiceHandle(hService);
	CloseServiceHandle(hSCM);

}


void CServiceControlDlg::StopServiceByName(CString csShortName)
{
	//Given an individual short name, stops the associated service.

	//Mostly ugly SERVICE structs
	CString csServiceName;
	BOOL bStopResult;
	DWORD dwError;
	SC_HANDLE hSCM;
	SC_HANDLE hService;
	SERVICE_STATUS ssStatus;

	//Get the service name
	csServiceName = MakeServiceName(csShortName);

	//Open the service handler
	hSCM = openSCM();
	//And get the handle of the service
	hService = openSvc(hSCM, csServiceName);

	//Try to stop it. If it fails, we'll find out at the next update
	bStopResult = ControlService(hService,SERVICE_CONTROL_STOP,&ssStatus);
	if(!bStopResult)
	{
		//Get the error for debugging
		dwError = GetLastError();
	}

	//Clean Up
	CloseServiceHandle(hService);
	CloseServiceHandle(hSCM);

}


void CServiceControlDlg::StartAll()
{
	//A flag to do simplified updates
	m_bStarting = true;
	
	//Invalidate the buttons
	//Disable "Stop All" Button
	CButton * cBTN = (CButton *) GetDlgItem(IDC_BTNSTOPALL);
	cBTN->EnableWindow(FALSE);
	//Change text on"Start All" Button
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTARTALL);
	cBTN->SetWindowText("Starting...");

	//Disable the rest of the buttons
	//Hold the old values, to reenable correctly
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTART);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTOP);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNSETSTOPMSG);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDOK);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNKILL);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNKILLALL);
	cBTN->EnableWindow(FALSE);
	CMenu* mnu = GetSystemMenu(FALSE);
	mnu->EnableMenuItem(SC_CLOSE,MF_BYCOMMAND | MF_GRAYED );

	//Loop through, starting and redrawing
	int nIndex;
	for(nIndex = 0; nIndex < m_iNumServices; nIndex++)
	{
		StartServiceByName(m_pcaServicesShortName[nIndex]);
		UpdateAll();
	}

	//Change the text back on the "Start All" Button
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTARTALL);
	cBTN->SetWindowText("Start All");
	cBTN->EnableWindow(FALSE);

	//Reenable the close box and close menu command
	cBTN = (CButton *) GetDlgItem(IDOK);
	cBTN->EnableWindow(TRUE);
	mnu = GetSystemMenu(FALSE);
	mnu->EnableMenuItem(SC_CLOSE,MF_BYCOMMAND | MF_ENABLED );

	//Clean up
	m_bStarting = false;
	UpdateAll();



}

void CServiceControlDlg::StopAll()
{
	//A flag to do simplified updates
	m_bStarting = true;

	//Change Text and Disable "Stop All" Button
	CButton * cBTN = (CButton *) GetDlgItem(IDC_BTNSTOPALL);
	cBTN->SetWindowText("Stopping...");
	//Disable "Start All" Button
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTARTALL);
	cBTN->EnableWindow(FALSE);

	//Disable the rest of the buttons
	//Hold the old values, to reenable correctly
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTART);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTOP);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNSETSTOPMSG);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNKILL);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNKILLALL);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDOK);
	cBTN->EnableWindow(FALSE);
	CMenu* mnu = GetSystemMenu(FALSE);
	mnu->EnableMenuItem(SC_CLOSE,MF_BYCOMMAND | MF_GRAYED );

	//Loop through, stopping and redrawing
	int nIndex;
	for(nIndex = 0; nIndex < m_iNumServices; nIndex++)
	{
		StopServiceByName(m_pcaServicesShortName[nIndex]);
		UpdateAll();
	}

	//Change the text back on the "Stop All" Button
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTOPALL);
	cBTN->SetWindowText("Stop All");
	cBTN->EnableWindow(FALSE);

	//Reenable the close button and menu item
	cBTN = (CButton *) GetDlgItem(IDOK);
	cBTN->EnableWindow(TRUE);
	mnu = GetSystemMenu(FALSE);
	mnu->EnableMenuItem(SC_CLOSE,MF_BYCOMMAND | MF_ENABLED );

	//Clean up
	m_bStarting = false;
	UpdateAll();
}


void CServiceControlDlg::OnBtnstartall() 
{
	//The only thing we need to trap here is two quick clicks
	if(!m_bStarting)
		StartAll();
}

void CServiceControlDlg::OnBtnstopall() 
{
	//The only thing we need to trap here is two quick clicks
	if(!m_bStarting)
		StopAll();
}

void CServiceControlDlg::SetButtonStates()
{

	//Set the states of the buttons depending on the state of the items selected

	//Start with all the items off, and turn them on as needed
	//Helpers
	CString csState;
	bool bStartButton = false;
	bool bStopButton = false;
	bool bSetStopMsgButton = false;
	bool bKillButton = true;

	POSITION p;

	//Loop through, turning on buttons for each service that 
	//Can do something (NON-EXCLUSIVE)
	p = m_LCServiceList.GetFirstSelectedItemPosition();
	while (p)
	{
		int nSelected = m_LCServiceList.GetNextSelectedItem(p);

		csState = m_LCServiceList.GetItemText(nSelected,1);
		
		//Remember, if it's not declared here, it's (all) OFF
		//We only need to handle cases where a user can do something
        if (csState.Find("Running")!=-1)
		{
			bStopButton = true;
			bKillButton = true;
			bSetStopMsgButton = true;
		}
		else if (csState == "Stopped")
		{
			bStartButton = true;
			bKillButton = false;
		}
	}

	// Ensure that "Kill" is disabled if we believe that the user
	// doesn't have access to do so
	bKillButton &= m_bKillPossible;

	//Set the buttons themselves
	CButton * cBTN = (CButton *) GetDlgItem(IDC_BTNSTART);
	cBTN->EnableWindow(bStartButton);
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTOP);
	cBTN->EnableWindow(bStopButton);
	cBTN = (CButton *) GetDlgItem(IDC_BTNKILL);
	cBTN->EnableWindow(bKillButton);
	cBTN = (CButton *) GetDlgItem(IDC_BTNSETSTOPMSG);
	cBTN->EnableWindow(bSetStopMsgButton);
	
}


int CServiceControlDlg::GetIndex(CString csShortName)
{
	//Find the index of csShortName in the list control.
	//We just use the CListCtrl::FindItem method.

	LVFINDINFO lvfo;
	int nItemIndex=-1;

	//Look it up the shortname in the list control
	lvfo.flags = LVFI_PARTIAL|LVFI_STRING;
	lvfo.psz = csShortName.GetBuffer();
	nItemIndex = m_LCServiceList.FindItem(&lvfo);
	csShortName.ReleaseBuffer();

	return nItemIndex;

}


void CServiceControlDlg::SetStopMsg(CString csShortName, CString csStopMsg)
{
	//Set the stop message, in both the registry and the service manager

	//Reg vars
	HKEY hKey;
	char szKey[256];
	DWORD dwDisp;

	//Service control vars
	SC_HANDLE hSCM;
	SC_HANDLE hService;
	SERVICE_STATUS sStatus;
	BOOL bSuccess = false;
	DWORD dwError;

	//Helper
	CString csServiceName;

	//First, in the registry - Build a key
	csServiceName = MakeServiceName(csShortName);
	strcpy_s(szKey, sizeof(szKey), "SYSTEM\\CurrentControlSet\\Services\\");
	strcat_s(szKey, sizeof(szKey), csServiceName);
	strcat_s(szKey, sizeof(szKey), "\\StopMsg");
	
	//And set it
	if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, "", REG_OPTION_VOLATILE, KEY_WRITE, NULL, &hKey, &dwDisp))
	{
		int32 msglen = csStopMsg.GetLength();
		char* msg = csStopMsg.GetBuffer();
		RegSetValueEx(hKey, "Msg", 0, REG_SZ, (BYTE*)msg, msglen);
		RegCloseKey(hKey);
		csStopMsg.ReleaseBuffer();
	}
	else
	{
		return;
	}

	//Now set it in the service control manager
	hSCM = openSCM();
	hService = openSvc(hSCM, csServiceName);
	bSuccess = ControlService(hService, SERVICE_CONTROL_SETSTOPMSG, &sStatus);

	if(!bSuccess)
	{
		dwError = GetLastError();
		return;
	}

	//Clean Up
	CloseServiceHandle(hService);
	CloseServiceHandle(hSCM);

}


void CServiceControlDlg::StopMsgWindow(int nItemIndex)
{
	//Handle the ui part of setting a stop message,
	//and then call SetStopMsg for every highlighted message
	//We get the one from the index in nItemIndex

	CString csStopMsg;
	CString csShortName;
	CString csServiceName;
	CString csAppName;
	CStopMsgDlg smDlg;
	POSITION p;

	//Get the stop message from the item(index) in the list
	csShortName   = m_LCServiceList.GetItemText(nItemIndex,0);
	csServiceName = MakeServiceName(csShortName);
	csAppName     = MakeAppName(csShortName);

	//Send it to the dialog, and let the user set the stopmsg
	csStopMsg = GetStopMsg(csServiceName);
	if(csStopMsg.Find("<None>")==-1)
	{
		smDlg.m_csStopMsg = csStopMsg;
	}
	if(smDlg.DoModal() == IDOK)
	{
		csStopMsg = smDlg.m_csStopMsg;
	}
	else
	{
		return;
	}

	//Set the stopmsg for each selected one
	p = m_LCServiceList.GetFirstSelectedItemPosition();
	while (p)
	{
		int nSelected = m_LCServiceList.GetNextSelectedItem(p);
		csShortName = m_LCServiceList.GetItemText(nSelected,0);
		SetStopMsg(csShortName,csStopMsg);
		UpdateSingleItem(csShortName, csAppName);
	}
	
}

void CServiceControlDlg::OnItemChangedInList(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

	//An item has changed... Find out if it's got the focus.. If it does, set m_iFocusIndex
	if ((pNMListView->uNewState & LVIS_FOCUSED) && !(pNMListView->uOldState & LVIS_FOCUSED))
	{	
		//We have a new focus - set the member var, and update the buttons
		m_iFocusIndex = pNMListView->iItem;
		SetButtonStates();
		return;
	}
	//Update the buttons based on the new focus
	SetButtonStates();
	*pResult = 0;
}


void CServiceControlDlg::SetFocusOnly(int nFocusIndex)
{

	//Unselect Everyone
	POSITION p = m_LCServiceList.GetFirstSelectedItemPosition();
	if (p == NULL)
	{	
		//Nothing was selected to begin with
		true;
	}
	else
	{
		while (p)
		{
		  int nIndex = m_LCServiceList.GetNextSelectedItem(p);
			//Deselected it
		  m_LCServiceList.SetItemState(nIndex, 0, LVIS_SELECTED);		
		}
	}

	//Set the focus here
	m_LCServiceList.SetFocus();

	//Select and focus the first one
	m_LCServiceList.SetItemState(nFocusIndex, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
	m_LCServiceList.EnsureVisible(nFocusIndex, FALSE);

	SetButtonStates();

	//Don't forget to update m_iFocusIndex
	m_iFocusIndex = nFocusIndex;
	m_iLastFocusIndex = 0;
}


void CServiceControlDlg::OnBtnsetstopmsg() 
{

	//Okay, if the focusIndex isn't selected, just get the first selected one
	if(m_LCServiceList.GetItemState(m_iFocusIndex, LVIS_SELECTED) == LVIS_SELECTED)
		StopMsgWindow(m_iFocusIndex);
	else
	{
		POSITION p = m_LCServiceList.GetFirstSelectedItemPosition();
		if (p == NULL)
		{	
			//Nothing was selected to begin with
			AfxMessageBox("Please select one or more items in the list first",MB_OK);
		}
		else
		{
			int nIndex = m_LCServiceList.GetNextSelectedItem(p);
			m_iFocusIndex = nIndex;
			StopMsgWindow(m_iFocusIndex);
		}
	}
}


void CServiceControlDlg::OnBtnstart() 
{
	//start all the highlighted services, and then reset the buttons
	POSITION p;
	CString csShortName;

	//Change the name on this one, and disable the rest
	m_bStarting = true;
	CButton * cBTN = (CButton *) GetDlgItem(IDC_BTNSTART);
	cBTN->SetWindowText("Starting...");
	//Disable "Start All" Button
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTARTALL);
	cBTN->EnableWindow(FALSE);

	//Disable the rest of the buttons
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTOP);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTOPALL);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNSETSTOPMSG);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTOPALL);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNKILL);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNKILLALL);
	cBTN->EnableWindow(FALSE);

	cBTN = (CButton *) GetDlgItem(IDOK);
	cBTN->EnableWindow(FALSE);
	CMenu * mnu = GetSystemMenu(FALSE);
	mnu->EnableMenuItem(SC_CLOSE,MF_BYCOMMAND | MF_GRAYED );

	//Do the actual starting
	p = m_LCServiceList.GetFirstSelectedItemPosition();
	while (p)
	{
		int nSelected = m_LCServiceList.GetNextSelectedItem(p);
		csShortName = m_LCServiceList.GetItemText(nSelected,0);
		StartServiceByName(csShortName);
		UpdateAll();

	}

	//Change the name back on this one
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTART);
	cBTN->SetWindowText("Start");
	//And reEnable the quit button
	cBTN = (CButton *) GetDlgItem(IDOK);
	cBTN->EnableWindow(TRUE);
	mnu = GetSystemMenu(FALSE);
	mnu->EnableMenuItem(SC_CLOSE,MF_BYCOMMAND | MF_ENABLED );

	//Clean up
	m_bStarting = false;
	SetButtonStates();
	UpdateAll();	

}

void CServiceControlDlg::OnBtnstop() 
{

	//Stop all the highlighted services, and then reset the buttons
	POSITION p;
	CString csShortName;

	//Change the name on this one, and disable the rest
	m_bStarting = true;
	CButton * cBTN = (CButton *) GetDlgItem(IDC_BTNSTOP);
	cBTN->SetWindowText("Stopping...");

	//Disable the rest of the buttons
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTARTALL);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTART);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTOPALL);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNSETSTOPMSG);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNKILL);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNKILLALL);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDOK);
	cBTN->EnableWindow(FALSE);
	CMenu * mnu = GetSystemMenu(FALSE);
	mnu->EnableMenuItem(SC_CLOSE,MF_BYCOMMAND | MF_GRAYED);

	//Do the actual stopping
	p = m_LCServiceList.GetFirstSelectedItemPosition();
	while (p)
	{
		int nSelected = m_LCServiceList.GetNextSelectedItem(p);
		csShortName = m_LCServiceList.GetItemText(nSelected,0);
		StopServiceByName(csShortName);
		UpdateAll();

	}

	//Change the name back on this one
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTOP);
	cBTN->SetWindowText("Stop");
	//And reEnable the quit button
	cBTN = (CButton *) GetDlgItem(IDOK);
	cBTN->EnableWindow(TRUE);
	mnu = GetSystemMenu(FALSE);
	mnu->EnableMenuItem(SC_CLOSE,MF_BYCOMMAND | MF_ENABLED );

	//Clean up
	m_bStarting = false;
	SetButtonStates();
	UpdateAll();	
}


int CServiceControlDlg::GetProcessId(CString csShortName)
{
	//Service Structures
	SC_HANDLE hSCM;
	SC_HANDLE hService;
	SC_STATUS_TYPE hStatusType = SC_STATUS_PROCESS_INFO ;
	SERVICE_STATUS_PROCESS hStatus;
	DWORD pid = 0;
	CString csServiceName;
	DWORD cbBufSize;
	DWORD pcbBytesNeeded = 0;

	//Get the Service from the Service Manager
	csServiceName = MakeServiceName(csShortName);
	hSCM = openSCM();
	hService = openSvc(hSCM, csServiceName);

	//Get a valid State and Error/Exit Code
	if(hService) // We got it
	{
		//Fill the Service Status Structure
		memset(&hStatus,0,sizeof(hStatus));
		cbBufSize = sizeof(hStatus);
		QueryServiceStatusEx(hService, hStatusType, (LPBYTE) &hStatus, cbBufSize, &pcbBytesNeeded);
		pid = hStatus.dwProcessId;
	}

	CloseServiceHandle(hService);
	CloseServiceHandle(hSCM);


	return pid;

}

void CServiceControlDlg::OnBtnkill() 
{
	//Make sure they meant to
	if(AfxMessageBox("This will end the selected services immediately, with errors. It should only be used in emergencies. Continue?", MB_YESNO) != IDYES)
		return;

	//kill all the highlighted services, and then reset the buttons
	POSITION p;
	CString csShortName;

	//Change the name on this one, and disable the rest
	m_bStarting = true;
	CButton * cBTN = (CButton *) GetDlgItem(IDC_BTNKILL);
	cBTN->SetWindowText("Killing...");

	//Disable the rest of the buttons
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTARTALL);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTOP);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTART);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTOPALL);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNSETSTOPMSG);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNKILLALL);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDOK);
	cBTN->EnableWindow(FALSE);
	CMenu * mnu = GetSystemMenu(FALSE);
	mnu->EnableMenuItem(SC_CLOSE,MF_BYCOMMAND | MF_GRAYED );

	//Do the actual killing
	p = m_LCServiceList.GetFirstSelectedItemPosition();
	while (p)
	{
		int nSelected = m_LCServiceList.GetNextSelectedItem(p);
		csShortName = m_LCServiceList.GetItemText(nSelected,0);
		KillByShortName(csShortName);
		UpdateAll();
	}

	//Change the name back on this one
	cBTN = (CButton *) GetDlgItem(IDC_BTNKILL);
	cBTN->SetWindowText("Kill");
	//And reEnable the quit button
	cBTN = (CButton *) GetDlgItem(IDOK);
	cBTN->EnableWindow(TRUE);
	mnu = GetSystemMenu(FALSE);
	mnu->EnableMenuItem(SC_CLOSE,MF_BYCOMMAND | MF_ENABLED );

	//Clean up
	m_bStarting = false;
	SetButtonStates();
	UpdateAll();	
}


void CServiceControlDlg::KillByShortName(CString csShortName)
{
	int pid;

	//Get the PID from the service
	pid = GetProcessId(csShortName);

	//Now kill it
	killmain(pid);

}


void CServiceControlDlg::OnBtnkillall() 
{	
	//Just make sure it's not the second of two quick clicks
	if(!m_bStarting)
		KillAllServices();

}

void CServiceControlDlg::KillAllServices()
{
	//Make sure they meant to
	if(AfxMessageBox("This will end all services immediately, with errors. It should only be used in emergencies. Continue?", MB_YESNO) != IDYES)
		return;

	//kill all the highlighted services, and then reset the buttons
	CString csShortName;

	//Change the name on this one, and disable the rest
	m_bStarting = true;
	CButton * cBTN = (CButton *) GetDlgItem(IDC_BTNKILLALL);
	cBTN->SetWindowText("Killing...");

	//Disable the rest of the buttons
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTARTALL);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTOP);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTART);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNSTOPALL);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNSETSTOPMSG);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDC_BTNKILL);
	cBTN->EnableWindow(FALSE);
	cBTN = (CButton *) GetDlgItem(IDOK);
	cBTN->EnableWindow(FALSE);
	CMenu * mnu = GetSystemMenu(FALSE);
	mnu->EnableMenuItem(SC_CLOSE,MF_BYCOMMAND | MF_GRAYED );

	//Do the actual killing
	int nIndex;
	for(nIndex = 0; nIndex < m_iNumServices; nIndex++)
	{
		KillByShortName(m_pcaServicesShortName[nIndex]);
		UpdateAll();

	}

	//Change the name back on this one
	cBTN = (CButton *) GetDlgItem(IDC_BTNKILLALL);
	cBTN->SetWindowText("Kill All");
	//And reEnable the quit button
	cBTN = (CButton *) GetDlgItem(IDOK);
	cBTN->EnableWindow(TRUE);
	mnu = GetSystemMenu(FALSE);
	mnu->EnableMenuItem(SC_CLOSE,MF_BYCOMMAND | MF_ENABLED );

	//Clean up
	m_bStarting = false;
	SetButtonStates();
	UpdateAll();		
}


// Try to open the SCM with full access. If that fails, try a conservative
// fallback before failing entirely, and record that initial failure.
SC_HANDLE CServiceControlDlg::openSCM()
{
	SC_HANDLE hSCM = NULL;

	hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if (hSCM)
		// The theory here is that, since the SCM is not directly securable
		// (at least not yet), the function call above is a sufficient test 
		// for root. (In other words, if you're here, you can kill you some
		// services, too.)
		m_bKillPossible = true;
	else
	{
		hSCM = OpenSCManager(NULL, NULL, GENERIC_READ);
		m_bKillPossible = false;
	}

	return hSCM;
}

// Try to open the named service with full access. If that fails, try a 
// conservative fallback before failing entirely.
SC_HANDLE CServiceControlDlg::openSvc(SC_HANDLE hSCM, LPCTSTR serviceName)
{
	SC_HANDLE hSvc = NULL;

	hSvc = OpenService(hSCM, serviceName, SERVICE_ALL_ACCESS);
	if (!hSvc)
		hSvc = OpenService(hSCM, serviceName, SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | 
		                                      SERVICE_START | SERVICE_STOP | SERVICE_USER_DEFINED_CONTROL);
	
	return hSvc;
}



void CServiceControlDlg::OnCbnSelchangeCombologlevel()
{
	CString sShortName;

	CComboBox* cmbLogLevel = (CComboBox*)GetDlgItem(IDC_COMBOLOGLEVEL);

	// New log level
	CString sLevel;
	cmbLogLevel->GetLBText(cmbLogLevel->GetCurSel(), sLevel);

	// Ask for confirmation
	CString csConfirm;
	csConfirm.Format("Set the Log level of all services to %s?", sLevel);
	if(AfxMessageBox(csConfirm, MB_YESNO) != IDYES)
	{
		return;
	}

	// Modify log level in server.ini
	if (!CasinoBase::setStrOptEx("LOG", "LogLevel", (char *)(LPCTSTR)sLevel))
	{
		// Error, no se ha podido escribir en fichero 
		AfxMessageBox("server.ini file could not be updated",MB_OK);		
		return;
	}

	// Send control service command to all services
	int nIndex;
	for(nIndex = 0; nIndex < m_iNumServices; nIndex++)
	{
		//Update each service listed individually
		sShortName = m_pcaServicesShortName[nIndex];
		SetLogLevel(sShortName);
	}

	/*
	// Iterate through services
	p = m_LCServiceList.getfirst
	while (p)
	{
		int nSelected = m_LCServiceList.GetNextSelectedItem(p);
		sShortName = m_LCServiceList.GetItemText(nSelected,0);

		CString csConfirm;
		csConfirm.Format("Set the Log level of all services to %s?", sLevel);
		if(AfxMessageBox(csConfirm, MB_YESNO) != IDYES)
			continue;

		SetLogLevel(sShortName, sLevel);
		
	}
	*/
}

//void CServiceControlDlg::OnCbnDropdownCombologlevel()
//{
//	// TODO: Add your control notification handler code here
//	return;
//}

void CServiceControlDlg::SetLogLevel(CString ServiceName)
{
	//Mostly ugly SERVICE structs
	CString csServiceName;
	BOOL bControlResult;
	SC_HANDLE hSCM;
	SC_HANDLE hService;
	SERVICE_STATUS ssStatus;

	//Get the service name
	csServiceName = MakeServiceName(ServiceName);

	//Open the service handler
	hSCM = openSCM();
	//And get the handle of the service
	hService = openSvc(hSCM, csServiceName);

	//Try to start it. If it fails, we'll find out at the next update
	bControlResult = ControlService(hService, SERVICE_CONTROL_SETLOGLEVEL, &ssStatus);
	if(!bControlResult)
	{
		//Get the error for debugging
		CString sMessage;
		sMessage.Format("Service control could not be sent to %s service", ServiceName);
		AfxMessageBox(sMessage,MB_OK);		
	}

	//Clean Up
	CloseServiceHandle(hService);
	CloseServiceHandle(hSCM);
}

